use std::path::Path;
use std::fs::File;
use std::io::Write;
use std::io::{BufRead, BufReader};
use super::sphere::Sphere;
use super::traits::Skynet;
use super::distance;

pub struct Points<'a, T> {
    pub n: usize, // 维度
    pub name: &'a str, // 名字
    pub body: Vec<Vec<T>>
}

impl<'a, T: Skynet<T>> Points<'a, T> {
    pub fn new(n: usize, name: &'a str) -> Points<'a, T> {
        return Points {n: n, name: name, body: Vec::new()};
    }
    pub fn load(&mut self, path: &Path) {
        let file = File::open(path).unwrap();
        let buf = BufReader::new(file);
        for line in buf.lines() {
            let mut p: Vec<T> = Vec::new();
            for x in line.unwrap().split_whitespace() {
                p.push(x.parse().unwrap());
            }
            self.body.push(p);
        }
    }
    pub fn bounding_sphere(&self) -> Sphere<T> {
        let mut sphere: Sphere<T> = Sphere::new(self.n);
        // 计算包围球中心
        let n: T = (self.body.len() as f64).into();
        for x_i in &self.body {
            for j in 0 .. self.n {
                sphere.center[j] += x_i[j] / n;
            }
        }
        // 计算包围球半径
        for x in &self.body {
            let d = distance(x, &sphere.center);
            if sphere.radius < d {
                sphere.radius = d;
            }
        }
        return sphere;
    }
    pub fn output_model(&self) {
        assert_eq!(self.n, 3);
        // 输出数据
        let mut points = String::new();
        points += format!("#declare {}_data = union {{\n", self.name).as_str();
        for p in &self.body {
            points += format!("  sphere {{<{:.6}, {:.6}, {:.6}> point_size}}\n",
                              p[0], p[1], p[2].inv()/* 右手系 -> 左手系 */).as_str();
        }
        points += "}\n";
        let mut points_file =
            File::create(Path::new(format!("{}.inc", self.name).as_str())).unwrap();
        points_file.write_all(points.as_bytes()).unwrap();
        // 输出 Povray 场景对象
        let mut object = String::new();
        object += "#include \"textures.inc\"\n";
        object += format!("#include \"{}.inc\"\n", self.name).as_str();
        object += "object {\n";
        object += format!("  {}_data\n", self.name).as_str();
        object += "  texture {Rust scale 0.3 * sky_r}\n";
        object+= "}\n\n";
        let object_path = format!("{}_object.inc", self.name);
        let mut object_file = File::create(Path::new(object_path.as_str())).unwrap();
        object_file.write_all(object.as_bytes()).unwrap();
    }
}
